package org.zpmis.common.service;


import com.alibaba.fastjson.JSON;
import com.google.common.base.Throwables;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.zpmis.common.annotations.ServiceLog;
import org.zpmis.common.exception.BusinessException;
import org.zpmis.common.mapper.CrudMapper;
import org.zpmis.common.utils.StringUtil;
import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 基于通用MyBatis Mapper插件的Service接口的实现
 */
@Slf4j
public abstract class AbstractService<T> implements Service<T> {

    @Autowired
    protected CrudMapper<T> mapper;

    /**
     * 当前泛型真实类型的Class
     */
    private Class<T> modelClass;

    public AbstractService() {
        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
        modelClass = (Class<T>) pt.getActualTypeArguments()[0];
    }

    @Override
    @ServiceLog(description = "持久化")
    public int save(T model) {
        return mapper.insertSelective(model);
    }

    @Override
    @ServiceLog(description = "批量持久化")
    public int save(List<T> models) {
        return mapper.insertList(models);
    }

    @Override
    @ServiceLog(description = "通过主鍵刪除")
    public int deleteById(Serializable id) {
        return mapper.deleteByPrimaryKey(id);
    }

    @Override
    @ServiceLog(description = "通过主鍵批量刪除")
    public int deleteByIds(String ids) {
        return mapper.deleteByIds(ids);
    }

    @Override
    @ServiceLog(description = "更新")
    public int update(T model) {
        return mapper.updateByPrimaryKeySelective(model);
    }

    @Override
    @ServiceLog(description = "通过ID查找")
    public T findById(Serializable id) {
        return mapper.selectByPrimaryKey(id);
    }


    @Override
    @ServiceLog(description = "通过多个ID查找")
    public List<T> findByIds(String ids) {
        if(StringUtil.isEmpty(ids)){
            return new ArrayList<>();
        }
        return mapper.selectByIds(ids);
    }

    /**
     * 该接口不适合远程调用 因为Condition类没有实现序列化接口 只能项目内部调用
     * @param condition
     * @return
     */
    @Override
    @ServiceLog(description = "根据条件查找")
    public List<T> findByCondition(Condition condition) {
        return mapper.selectByCondition(condition);
    }

    @Override
    @ServiceLog(description = "获取所有")
    public List<T> findAll() {
        return mapper.selectAll();
    }

    @Override
    @ServiceLog(description = "根据自定义条件查找")
    public T findBy(String fieldName, Object value) throws BusinessException {
        try {
            T model = modelClass.newInstance();
            Field field = modelClass.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(model, value);
            return mapper.selectOne(model);
        } catch (ReflectiveOperationException e) {
            throw new BusinessException(e.getMessage(), e);
        }
    }

    @Override
    @ServiceLog(description = "根据Map条件查找")
    public List<T> findByConditionMap(Map<String, Object> params) {
        List<T> resultList = new ArrayList<>();
        try {
            Condition condition = new Condition(modelClass);
            Example.Criteria criteria = condition.createCriteria();
            params.forEach((k, v) -> {
                criteria.andEqualTo(k, v);
            });
            resultList = this.findByCondition(condition);

        } catch (Exception e) {
            log.error("findByConditionMap--Exception, exception:{}, caused by: {}",  e.getClass(), Throwables.getStackTraceAsString(e));
            throw new BusinessException(e.getMessage(), e);
        }
        return resultList;
    }

    @Override
    @ServiceLog(description = "根据model查找")
    public T findByModel(Map<String,Object> map) {
        T model = JSON.parseObject(JSON.toJSONString(map), (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        //T model = GsonUtil.toPojo(GsonUtil.toJsonString(map),(Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        return mapper.selectOne(model);
    }

}
